package wx.wechat.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.squareup.okhttp.*;
import lombok.SneakyThrows;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.DocumentException;
import wx.wechat.common.Configure;
import wx.wechat.common.signature.Signature;
import wx.wechat.utils.XMLUtils;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @function 封装一些常用的方法
 */
public class WXService {


    public final String OPEN_API_WEIXIN_HOST = "open.weixin.qq.com";

    public final String API_WEIXIN_HOST = "api.weixin.qq.com";

    private final OkHttpClient client = new OkHttpClient();

    private static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/xml; charset=utf-8");


    /**
     * @param host
     * @param path
     * @param params 参数对,必须是双数
     * @return
     */
    @SneakyThrows
    protected Map<String, String> getWithParams(String host, String path, Map<String, String> params) throws IOException {

        //预设的返回的数据集
        Map<String, String> result = new HashMap<>();

        //构建请求路径
        HttpUrl.Builder httpUrlBuilder = new HttpUrl.Builder()
                .scheme("https")
                .host(host);

        //将Path重新解构依次赋值给URL
        Arrays.stream(path.split("/")).forEach(s -> {
            httpUrlBuilder.addPathSegment(s);
        });


        //添加查询参数
        params.forEach((k, v) -> {
            httpUrlBuilder.addEncodedQueryParameter(k, v);
        });

        //构建请求
        Request request = new Request.Builder()
                .url(httpUrlBuilder.build())
                .get()
                .build();

        System.out.println(request);
        System.out.println(JSON.toJSON(request));

        //发起请求
        Response response = client.newCall(request).execute();

        System.out.println(response);
        System.out.println(JSON.toJSON(response));

        //解析获取的数据并且返回Map
        JSONObject.parseObject(response.body().string()).forEach((k, v) -> {
            result.put(k, String.valueOf(v));
        });

        return result;
    }

    /**
     * @param url         待请求的URL的地址
     * @param requestData 请求的数据
     * @return
     * @function 根据输入的数据向URL发起请求, 并且进行自动的签名
     */
    @SneakyThrows
    protected Map<String, Object> postByXML(String url, Map requestData) throws IOException, DocumentException {

        //首先获取签名,注意,这里的签名用的是微信支付的签名
        String signature = Signature.getSign4Pay(requestData);

        //签名添加到请求数据中
        requestData.put("sign", signature);

        System.out.println("requestData " + requestData);

        //封装成XML数据
        String requestXML = XMLUtils.convertToXML(requestData);

        //调用okHttp发起请求
        Request request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, requestXML))
                .build();

        Response response = client.newCall(request).execute();

        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

        return XMLUtils.XML2Map(response.body().string());
    }

    /**
     * @param url         待请求的URL的地址
     * @param requestData 请求的数据
     * @return
     * @function 根据输入的数据向URL发起请求, 并且进行自动的签名
     */
    @SneakyThrows
    protected Map<String, Object> postByXMLForSSL(String url, Map<String, String> requestData, String pks12path) throws Exception{

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        char[] passwd = Configure.mchID.toCharArray();
        InputStream instream = new FileInputStream(new File(pks12path));
        try {//mchID
            keyStore.load(instream, passwd);
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, passwd)
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        StringBuilder content = new StringBuilder();
        //企业转账
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-Type", "application/xml");

        System.out.println("executing request" + httpPost.getRequestLine());
        CloseableHttpResponse response = null;
        try {
            HttpEntity entityParam = new ByteArrayEntity(XMLUtils.convertToXML(requestData).getBytes("UTF-8"));
            httpPost.setEntity(entityParam);
            response = httpclient.execute(httpPost);
            HttpEntity entity = response.getEntity();

            if (entity != null) {
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                String text;
                while ((text = bufferedReader.readLine()) != null) {
                    content.append(text);
                }
            }
            EntityUtils.consume(entity);
        } finally {
            response.close();
            httpclient.close();
        }
        System.out.println("postByXMLForSSL : " + content.toString());
        return  XMLUtils.XML2Map(content.toString());
    }

    /**
     * @param url         待请求的URL的地址
     * @param requestJSON 请求的数据
     * @return
     * @function 根据输入的数据向URL发起请求
     */
    @SneakyThrows
    public String postByJSON(String url, String requestJSON) throws IOException, DocumentException {

        //调用okHttp发起请求
        Request request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, requestJSON))
                .build();

        Response response = client.newCall(request).execute();

        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

//        System.out.println(response.body().string());
        return response.body().string();
    }

    /**
     * @param url         待请求的URL的地址
     * @return
     * @function 根据输入的数据向URL发起请求
     */
    public String getByJSON(String url) throws IOException, DocumentException {

        //调用okHttp发起请求
        Request request = new Request.Builder()
                .url(url)
                .build();

        Response response = client.newCall(request).execute();

        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

        return response.body().string();
    }
}
